﻿using UnityEngine;
using UnityEngine.Audio;
using System.Collections.Generic;
using System;
namespace CalmNine.Framework
{
    public class AudioGroup
    {
        public GroupSetting Setting { get; private set; }
        private List<AudioPlayer> players;
        private AudioMixerGroup mixGroup;

        Dictionary<int, AudioPlayer> playingDict;
        public string Name => mixGroup.name;
        public string VolumeName => Name + "Volume";
        int serialId = 0;

        private Action mOnIdle;
        private Action mOnPlay;

        public IAudioLoader AudioLoder;

        public AudioGroup(IAudioLoader loader, GroupSetting setting, Transform root, AudioMixerGroup mixer)
        {
            this.AudioLoder = loader;
            this.mixGroup = mixer;
            this.Setting = setting;
            setting.Init();
            this.Mute = Setting.Mute.Value;
            this.players = new List<AudioPlayer>();
            this.playingDict = new Dictionary<int, AudioPlayer>();
            string groupName = Name;
            var group = new GameObject(groupName).transform;
            group.SetParent(root);
            for (int i = 0; i < setting.AudioPlayerCount; i++)
            {
                AudioPlayer player = new GameObject(groupName + "_" + i).AddComponent<AudioPlayer>();
                player.transform.SetParent(group);
                player.Init(this);
                players.Add(player);
                player.GetComponent<AudioSource>().outputAudioMixerGroup = mixGroup;
            }
        }

        public void SetOnPlay(Action onPlay)
        {
            this.mOnPlay = onPlay;
        }

        public void SetOnIdle(Action onIdle)
        {
            this.mOnIdle = onIdle;
        }

        public bool Mute
        {
            get
            {
                return Setting.Mute.Value;
            }
            set
            {
                //if (Setting.Mute.Value == value)
                //{
                //    return;
                //}
                Setting.Mute.Value = value;
                // 静音
                if (value)
                {
                    mixGroup.audioMixer.SetFloat(VolumeName, Remap01ToDB(0));
                }
                else
                {
                    //重置音量
                    if (Volume == 0)
                    {
                        Volume = 1;
                    }
                    // 恢复音量
                    else
                    {
                        mixGroup.audioMixer.SetFloat(VolumeName, Remap01ToDB(Volume));
                    }
                }
            }
        }

        public float Volume
        {
            get
            {
                return Setting.Volume.Value;
            }
            set
            {
                float temp = (float)Math.Round(value, 1);
                if (Setting.Volume.Value == temp)
                {
                    return;
                }
                // 声音太小 静音
                if (temp < 0.1f)
                {
                    temp = 0;
                    Mute = true;
                }
                Setting.Volume.Value = temp;
                // 取消静音
                if (temp > 0)
                {
                    Mute = false;
                }
                mixGroup.audioMixer.SetFloat(VolumeName, Remap01ToDB(temp));
            }
        }

        public void TempVolume(float volume)
        {
            mixGroup.audioMixer.SetFloat(VolumeName, Remap01ToDB(volume));
        }

        private float Remap01ToDB(float x)
        {
            if (x <= 0.0f) x = 0.0001f;
            return Mathf.Log10(x) * 20.0f;
        }

        AudioPlayer GetPlayer(AudioParam param)
        {
            AudioPlayer player = null;
            int Priority = param.Priority;
            foreach (AudioPlayer temp in players)
            {
                if (!temp.IsUsing)
                {
                    player = temp;
                    break;
                }
                // 找到优先级最低的播放器
                if (temp.Priority < Priority)
                {
                    Priority = temp.Priority;
                    player = temp;
                }
                // 如果可以同级替换，预制一个待替换Player
                else if (Setting.CanReplace && temp.Priority == Priority && player == null)
                {
                    Priority = temp.Priority;
                    player = temp;
                }
            }
            return player;
        }

        public bool Play(AudioClip clip, AudioParam param = null)
        {
            if (param == null)
            {
                param = Setting.Param.Clone(clip);
            }
            else
            {
                param.Clip = clip;
            }
            return Play(param);
        }

        public bool Play(string assetName, AudioParam param = null)
        {
            AudioClip clip = AudioLoder.LoadAudioClip("Audios/" + Name + "/" + assetName);
            if (!clip)
            {
                return false;
            }
            return Play(clip, param);
        }

        bool Play(AudioParam param)
        {
            if (param.Clip == null)
            {
                return false;
            }
            AudioPlayer player = GetPlayer(param);
            if (player != null)
            {
                int tempID = serialId++;
                OnPlayAudioFinally over = (a) =>
                {
                    OnFinlly(tempID);
                };
                if (param.OnFinally == null)
                {
                    param.OnFinally = over;
                }
                else
                {
                    param.OnFinally += over;
                }
                player.Play(tempID, param);
                playingDict.Add(tempID, player);
                mOnPlay?.Invoke();
            }
            return player != null;
        }

        public bool Stop(int serialId)
        {
            if (playingDict.ContainsKey(serialId))
            {
                playingDict[serialId].Stop();
                return true;
            }
            return false;
        }

        public bool Pause(int serialId)
        {
            if (playingDict.ContainsKey(serialId))
            {
                playingDict[serialId].Pause();
                return true;
            }
            return false;
        }

        public bool Resume(int serialId)
        {
            if (playingDict.ContainsKey(serialId))
            {
                playingDict[serialId].Resume();
                return true;
            }
            return false;
        }

        public void StopAll()
        {
            List<AudioPlayer> all = new List<AudioPlayer>();
            all.AddRange(playingDict.Values);
            foreach (AudioPlayer player in all)
            {
                player.Stop();
            }
        }

        void OnFinlly(int id)
        {
            playingDict.Remove(id);
            if (playingDict.Count == 0)
            {
                mOnIdle?.Invoke();
            }
        }

        public void ResumeAll()
        {
            foreach (AudioPlayer player in playingDict.Values)
            {
                player.Resume();
            }
        }
        public void PauseAll()
        {
            foreach (AudioPlayer player in playingDict.Values)
            {
                player.Pause();
            }
        }
    }
}
